package actors

import java.io.File

import akka.actor.PoisonPill
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.{ActorRef, Behavior, PostStop}
import akka.stream.Materializer
import command.{CommandExec, MissionUtils}
import dao.ModeDao
import models.Tables.MissionRow
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import shared.Pojo._
import tool.Pojo._
import tool.Tool

import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import implicits.Implicits._
import play.api.libs.ws.WSClient
import shared.VarTool


/**
 * Created by yz on 13/4/2020
 */
object MissionExecutor {

  def long2fat(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.long2fat(workspaceDir, resultDir)
    }.map { b =>
      Tool.long2fatResultDeal(workspaceDir, resultDir)
    }
  }

  def hJoin(workspaceDir: File, resultDir: File) = {
    CommandExec().exec { b =>
      Tool.hJoin(workspaceDir, resultDir)
    }.map { b =>
      Tool.long2fatResultDeal(workspaceDir, resultDir)
    }
  }

  def apply(mission: MissionRow)(implicit dao: MyDao, ws: WSClient, materializer: Materializer): Behavior[MissionAction] = Behaviors.setup { context =>
    Behaviors.receive[MissionAction] { (context, message) =>
      message match {
        case RunAction =>
          val missionDao = dao.missionDao
          val newMision = mission.copy(state = "running")
          val userId = mission.userId
          val outDir = Tool.getUserMissionKindDir(mission.userId, mission.kind)
          val missionDir = MissionUtils.getMissionDir(mission.id, outDir)
          val (workspaceDir, resultDir) = (missionDir.workspaceDir, missionDir.resultDir)
          val logFile = Tool.getLogFile(workspaceDir.getParentFile)
          missionDao.update(newMision).map { x =>
            val curSoft = Tool.kindSoftMap(mission.kind)
            val commandExec = curSoft.exec(workspaceDir, resultDir, 0)
            val state = if (commandExec.isSuccess) {
              "success"
            } else {
              commandExec.errorInfo.toFile(logFile)
              "error"
            }
            val newMission = mission.copy(state = state, endTime = Some(new DateTime()))
            missionDao.update(newMission).map { x =>
            }
          }.onComplete {
            case Failure(exception) =>
              exception.printStackTrace()
              FileUtils.writeStringToFile(logFile, exception.toString)
              val newMission = mission.copy(state = "error", endTime = Some(new DateTime()))
              missionDao.update(newMission).map { x =>
              }
              context.self ! Stop
            case Success(x) =>
              context.self ! Stop
          }
          Behaviors.same
        case Stop => Behaviors.stopped
      }
    }.receiveSignal { case (context, PostStop) =>
      Behaviors.stopped
    }
  }

}
